use core::ffi::c_void;
use core::fmt::{self, Write};

use crate::irq::{rt_hw_interrupt_disable, rt_hw_interrupt_enable};
use crate::rt_extern::dbg_uart_putc;

struct Stdout;

impl Write for Stdout {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        puts(s);
        Ok(())
    }
}

pub fn _print(args: fmt::Arguments) {
    Stdout.write_fmt(args).unwrap();
}

fn puts(s: &str) {
    let level = unsafe {rt_hw_interrupt_disable()};
    for c in  s.as_bytes() {
        unsafe {
            dbg_uart_putc(*c);
        }
    }
    unsafe {
        rt_hw_interrupt_enable(level);
    } 
}

#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ({
        $crate::kservice::_print(format_args!($($arg)*));
    });
}

#[macro_export]
macro_rules! println {
    () => ($crate::print!("\n"));
    ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
}


#[no_mangle]
pub extern "C" fn rt_memset(s: *mut c_void, c: i32, count: u32) -> *mut c_void {
    unsafe {
        let p = s as *mut u8;
        let v = c as u8;
        for i in 0..count {
            *(p.offset(i as isize)) = v;
        }
    }
    s
}

// char *rt_strncpy(char *dest, const char *src, rt_ubase_t n);
#[no_mangle]
pub extern "C" fn rt_strncpy(dest: *mut i8, src: *const i8, n: usize) -> *mut i8 {
    if n != 0 {
        for i in 0..n {
            let t;
            unsafe{ 
                t = *src.offset(i as isize);
            }
            if t == 0 {
                break;
            }
            unsafe {
                *dest.offset(i as isize) = t;
            }
        }
    }
    dest
}